package com.example.cameraxdemo

import android.Manifest
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.media.MediaScannerConnection
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.webkit.MimeTypeMap
import android.widget.Button
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.AspectRatio
import androidx.camera.core.Camera
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.ImageCaptureException
import androidx.camera.core.Preview
import androidx.camera.core.VideoCapture
import androidx.camera.core.VideoCapture.OnVideoSavedCallback
import androidx.camera.core.VideoCapture.OutputFileOptions
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.net.toFile
import com.blankj.utilcode.util.LogUtils
import com.example.cameraxdemo.activity.CameraActivity
import com.example.cameraxdemo.utils.Constants
import com.example.cameraxdemo.utils.Constants.Companion.DATE_FORMAT
import com.example.cameraxdemo.utils.Constants.Companion.PHOTO_EXTENSION
import com.example.cameraxdemo.utils.Constants.Companion.REQUIRED_PERMISSIONS
import com.example.cameraxdemo.utils.FileManager
import com.example.cameraxdemo.utils.ToastUtils
import com.example.cameraxdemo.utils.VideoFileUtils.createFile
import com.example.cameraxdemo.utils.VideoFileUtils.getOutputDirectory
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors

class MainActivity : AppCompatActivity() {
    private var imageCamera: ImageCapture? = null
    private lateinit var cameraExecutor: ExecutorService
    private var videoCapture: VideoCapture? = null
    private var cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA//当前相机
    private var preview: Preview? = null//预览对象
    private var cameraProvider: ProcessCameraProvider? = null//相机信息
    private lateinit var camera: Camera //相机对象
    private var isRecordVideo: Boolean = false
    private val TAG = "CameraXApp"
    private lateinit var outputDirectory: File
    private var lensFacing: Int = CameraSelector.LENS_FACING_BACK
    private val btnCameraCapture: Button by lazy { findViewById(R.id.btnCameraCapture) }
    private val btnVideo: Button by lazy { findViewById(R.id.btnVideo) }
    private val btnSwitch: Button by lazy { findViewById(R.id.btnSwitch) }
    private val btnOpenCamera: Button by lazy { findViewById(R.id.btnOpenCamera) }
    private val viewFinder: PreviewView by lazy { findViewById(R.id.mPreviewView) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initPermission()
        initView()
    }

    private fun initView() {
        outputDirectory = getOutputDirectory(this)
    }

    @SuppressLint("RestrictedApi")
    private fun initListener() {
        btnCameraCapture.setOnClickListener {
            takePhoto()
        }
        btnVideo.setOnClickListener {
            if (!isRecordVideo) {
                takeVideo()
                isRecordVideo = true
                btnVideo.text = "停止录像"
            } else {
                isRecordVideo = false
                videoCapture?.stopRecording()//停止录制
                //preview?.clear()//清除预览
                btnVideo.text = "开始录像"
            }
        }
        btnSwitch.setOnClickListener {
            cameraSelector = if (cameraSelector == CameraSelector.DEFAULT_BACK_CAMERA) {
                CameraSelector.DEFAULT_FRONT_CAMERA
            } else {
                CameraSelector.DEFAULT_BACK_CAMERA
            }
            if (!isRecordVideo) {
                startCamera()
            }
        }
        btnOpenCamera.setOnClickListener {
            val intent = Intent(this, CameraActivity::class.java)
            startActivity(intent)
        }
    }


    private fun initPermission() {
        if (checkPermissions()) {
            // ImageCapture
            startCamera()
        } else {
            requestPermission()
        }
    }

    private fun requestPermission() {
        when {
            Build.VERSION.SDK_INT >= 33 -> {
                ActivityCompat.requestPermissions(
                    this,
                    arrayOf(Manifest.permission.READ_MEDIA_IMAGES,Manifest.permission.READ_MEDIA_AUDIO,Manifest.permission.READ_MEDIA_VIDEO,Manifest.permission.CAMERA,Manifest.permission.RECORD_AUDIO),
                    Constants.REQUEST_CODE_PERMISSIONS
                )
            }

            else -> {
                ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, Constants.REQUEST_CODE_PERMISSIONS)
            }
        }
    }


    /**
     * 开始拍照
     */
    private fun takePhoto() {
        val imageCapture = imageCamera ?: return
        val photoFile = createFile(outputDirectory, DATE_FORMAT, PHOTO_EXTENSION)
        val metadata = ImageCapture.Metadata().apply {
            // Mirror image when using the front camera
            isReversedHorizontal = lensFacing == CameraSelector.LENS_FACING_FRONT
        }
        val outputOptions =
            ImageCapture.OutputFileOptions.Builder(photoFile).setMetadata(metadata).build()
        imageCapture.takePicture(outputOptions, ContextCompat.getMainExecutor(this),
            object : ImageCapture.OnImageSavedCallback {
                override fun onError(exc: ImageCaptureException) {
                    LogUtils.e(TAG, "Photo capture failed: ${exc.message}", exc)
                    ToastUtils.shortToast(" 拍照失败 ${exc.message}")
                }

                override fun onImageSaved(output: ImageCapture.OutputFileResults) {
                    val savedUri = output.savedUri ?: Uri.fromFile(photoFile)
                    ToastUtils.shortToast(" 拍照成功 $savedUri")
                    LogUtils.e(TAG, savedUri.path.toString())
                    val mimeType = MimeTypeMap.getSingleton()
                        .getMimeTypeFromExtension(savedUri.toFile().extension)
                    MediaScannerConnection.scanFile(
                        this@MainActivity,
                        arrayOf(savedUri.toFile().absolutePath),
                        arrayOf(mimeType)
                    ) { _, uri ->
                        LogUtils.d(
                            TAG,
                            "Image capture scanned into media store: ${uri.path.toString()}"
                        )
                    }
                }
            })
    }


    /**
     * 开始录像
     */
    @SuppressLint("RestrictedApi", "ClickableViewAccessibility", "MissingPermission")
    private fun takeVideo() {
        //开始录像
        try {
            isRecordVideo = true
            val mFileDateFormat = SimpleDateFormat(DATE_FORMAT, Locale.US)
            //视频保存路径
            val file =
                File(FileManager.getCameraVideoPath(), mFileDateFormat.format(Date()) + ".mp4")
            val outputOptions = OutputFileOptions.Builder(file)
            videoCapture?.startRecording(
                outputOptions.build(),
                Executors.newSingleThreadExecutor(),
                object : OnVideoSavedCallback {
                    override fun onVideoSaved(outputFileResults: VideoCapture.OutputFileResults) {
                        isRecordVideo = false
                        if(BuildConfig.DEBUG){
                            LogUtils.d(TAG, "===视频保存的地址为=== ${file.absolutePath}")
                        }
                        //保存视频成功回调，会在停止录制时被调用
                        ToastUtils.shortToast(" 录像成功 $file")
                    }

                    override fun onError(
                        videoCaptureError: Int,
                        message: String,
                        cause: Throwable?
                    ) {
                        //保存失败的回调，可能在开始或结束录制时被调用
                        isRecordVideo = false
                        if(BuildConfig.DEBUG) {
                            LogUtils.e(TAG, "onError: $message")
                        }
                        ToastUtils.shortToast(" 录像失败 $message")
                    }
                })
        } catch (e: Exception) {
            e.printStackTrace()
            if(BuildConfig.DEBUG) {
                LogUtils.e(TAG, "===录像出错===${e.message}")
            }
        }
    }

    /**
     * 开始相机预览
     */
    @SuppressLint("RestrictedApi")
    private fun startCamera() {
        cameraExecutor = Executors.newSingleThreadExecutor()
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        cameraProviderFuture.addListener(Runnable {
            cameraProvider = cameraProviderFuture.get()//获取相机信息

            //预览配置
            preview = Preview.Builder()
                .build()
                .also {
                    it.setSurfaceProvider(viewFinder.surfaceProvider)
                }

            imageCamera = ImageCapture.Builder()
                .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
                .build()

            videoCapture = VideoCapture.Builder()//录像用例配置
                .setTargetAspectRatio(AspectRatio.RATIO_16_9) //设置高宽比
                //.setTargetRotation(viewFinder.display!!.rotation)//设置旋转角度
                .build()
            try {
                cameraProvider?.unbindAll()//先解绑所有用例
                camera = cameraProvider?.bindToLifecycle(
                    this,
                    cameraSelector,
                    preview,
                    imageCamera,
                    videoCapture
                )!!//绑定用例
            } catch (e: Exception) {
                if(BuildConfig.DEBUG) {
                    LogUtils.e(TAG, "Use case binding failed", e.message)
                }
            }

        }, ContextCompat.getMainExecutor(this))
        initListener()
    }

    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<String>, grantResults:
        IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
                when (requestCode) {
                    Constants.REQUEST_CODE_PERMISSIONS -> {
                        var allPermissionsGranted = true
                        for (result in grantResults) {
                            if (result != PackageManager.PERMISSION_GRANTED) {
                                allPermissionsGranted = false
                                break
                            }
                        }
                        when {
                            allPermissionsGranted -> {
                                // 权限已授予，执行文件读写操作
                                startCamera()
                            }

                            else -> {
                                // 权限被拒绝，处理权限请求失败的情况
                                ToastUtils.shortToast("请您打开必要权限")
                                requestPermission()
                            }
                        }
                    }
                }
    }

    private fun checkPermissions(): Boolean {
        when {
            Build.VERSION.SDK_INT >= 33 -> {
                val permissions = arrayOf(
                    Manifest.permission.READ_MEDIA_IMAGES,
                    Manifest.permission.READ_MEDIA_AUDIO,
                    Manifest.permission.READ_MEDIA_VIDEO,
                    Manifest.permission.CAMERA,
                    Manifest.permission.RECORD_AUDIO,
                )
                for (permission in permissions) {
                    return Environment.isExternalStorageManager()
                }
            }

            else -> {
                for (permission in REQUIRED_PERMISSIONS) {
                    if (ContextCompat.checkSelfPermission(
                            this,
                            permission
                        ) != PackageManager.PERMISSION_GRANTED
                    ) {
                        return false
                    }
                }
            }
        }
        return true
    }

    override fun onDestroy() {
        super.onDestroy()
        cameraExecutor.shutdown()
    }
}